package com.tianji.learning.service.impl;

import com.tianji.common.utils.DateUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.domain.po.PointsRecord;
import com.tianji.learning.domain.vo.PointsStatisticsVO;
import com.tianji.learning.enums.PointsRecordType;
import com.tianji.learning.mapper.PointsRecordMapper;
import com.tianji.learning.service.IPointsRecordService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static com.tianji.common.constants.RedisConstants.POINT_BOARD_KEY_PREFIX;

/**
 * <p>
 * 学习积分记录，每个月底清零 服务实现类
 * </p>
 *
 * @author LYQ
 * @since 2024-06-30
 */
@Service
@RequiredArgsConstructor
public class PointsRecordServiceImpl extends ServiceImpl<PointsRecordMapper, PointsRecord> implements IPointsRecordService {
    private final StringRedisTemplate redisTemplate;
    /**
     * 新增积分记录
     *
     * @param userId
     * @param points
     * @param type
     */
    @Override
    public void addPointsRecord(Long userId, int points, PointsRecordType type) {
        //1、查询当日该用户对应的积分类型的积分获取总和
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime dayStartTime = DateUtils.getDayStartTime(now);
        LocalDateTime dayEndTime = DateUtils.getDayEndTime(now);
        PointsRecord pointsRecord = this.query()
                .select("sum(points) as points")
                .eq("type", type)
                .eq("user_id", userId)
                .between("create_time", dayStartTime, dayEndTime)
                .one();
        int sumPointsToday = 0;
        if (pointsRecord != null) {
            sumPointsToday = pointsRecord.getPoints();
        }
        int maxPoints = type.getMaxPoints();
        //如果当前分数超过了该类型积分记录的最大分数，则直接return
        if (sumPointsToday >= maxPoints && maxPoints != 0) {
            return;
        }
        //如果该类型积分记录有每日最大分数限制，则判断是否超过限制
        if (maxPoints != 0 && sumPointsToday + points > maxPoints) {
            points = maxPoints - sumPointsToday;
        }
        //保存该次积分记录
        PointsRecord record = new PointsRecord();
        record.setUserId(userId);
        record.setPoints(points);
        record.setType(type);
        save(record);
        //将本次积分累加到redis积分排行表中
        String dateStr = DateUtils.format(now, DateUtils.DATE_SUFFIX_FORMATTER);
        String pointBoardKey = POINT_BOARD_KEY_PREFIX + dateStr;
        redisTemplate.opsForZSet().incrementScore(pointBoardKey, userId.toString(), points);
    }

    /**
     * 查询当前用户的当肉积分统计情况
     *
     * @return
     */
    @Override
    public List<PointsStatisticsVO> queryPointsStatistics() {
        //1、根绝积分类型的枚举类初始化集合
        PointsRecordType[] values = PointsRecordType.values();
        List<PointsStatisticsVO> resultList = Arrays.stream(values).map(type -> {
            PointsStatisticsVO vo = new PointsStatisticsVO();
            vo.setType(type.getDesc());
            vo.setPoints(0);
            vo.setMaxPoints(type.getMaxPoints() == 0 ? 999 : type.getMaxPoints());
            return vo;
        }).collect(Collectors.toList());

        //2、分组查询当前用户当日的积分记录、
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime dayStartTime = DateUtils.getDayStartTime(now);
        LocalDateTime dayEndTime = DateUtils.getDayEndTime(now);
        List<PointsRecord> list = this.query()
                .select("sum(points) as points,type")
                .eq("user_id", UserContext.getUser())
                .between("create_time", dayStartTime, dayEndTime)
                .groupBy("type")
                .list();
        //将list转为map
        Map<String, Integer> pointMap = list.stream().map(pointsRecord -> {
            PointsStatisticsVO vo = new PointsStatisticsVO();
            vo.setType(pointsRecord.getType().getDesc());
            vo.setMaxPoints(pointsRecord.getType().getMaxPoints());
            vo.setPoints(pointsRecord.getPoints());
            return vo;
        }).collect(Collectors.toMap(PointsStatisticsVO::getType, PointsStatisticsVO::getPoints));
        //遍历resultlist，有分数的则覆盖
        for (PointsStatisticsVO pointsStatisticsVO : resultList) {
            pointsStatisticsVO.setPoints(pointMap.getOrDefault(pointsStatisticsVO.getType(), 0));
        }
        return resultList;
    }
}
